????ࡱ> ~9 Rbjbj2~lZZZZZZZn6666\l6nD|<78888888LDNDNDNDNDNDND$aF HPrD-Z88888rD=ZZ88D===8Z8Z8LD=8LD==>@ZZA807 P*Yn269@A4D0D@,H=HA=nnZZZZ HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutations.asp" http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutations.asp Using Permutations in .NET for Improved Systems Security Dr. James McCaffrey Volt Information Sciences, Inc. August 2003 Applies to:    Microsoft® .NET    C# Summary: Permutations are the backbone of all modern cryptosystems. By using permutations, you can increase the security of software systems. This article briefly explains what permutations are and provides the basis of a Permutation class implemented in C#, presents a short algorithm that solves the difficult problem of generating an arbitrary permutation by using a mathematical construct, and shows several practical applications of permutations, including block diffusion ciphers and programmatic generation of test cases. (22 printed pages) Contents  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutat_topic1" \t "_self" Introduction  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutat_topic2" \t "_self" A Permutation Class   HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutat_topic3" \t "_self" The kth Permutation of Order n  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutat_topic4" \t "_self" The Successor of a Given Permutation  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutat_topic5" \t "_self" Block Ciphers  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutat_topic6" \t "_self" Programmatic Generation of Test Cases  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutat_topic7" \t "_self" Random Permutations  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutat_topic8" \t "_self" Conclusion Introduction Permutations have a surprisingly wide range of uses in computer security. For example, the very first step in the Data Encryption Standard (DES) is to permute the input. In fact, permutations, along with substitutions, form the backbone of all modern cryptographic systems. In this article, I briefly describe what permutations are, provide you with a working Permutation class that contains a previously unpublished algorithm using a mathematical construct called the "factoradic," and show you how you can apply permutations to improve and test the security of software systems. A permutation is an arrangement of items where order matters. For example, all six permutations of the three words "apple", "banana", and "cherry" are: { apple, banana, cherry } { apple, cherry, banana } { banana, apple, cherry } { banana, cherry, apple } { cherry, apple, banana } { cherry, banana, apple } A mathematical permutation of order n is an arrangement of the numbers 0 through n-1. For example, a few of the 24 total permutations of order 4 are ( 0 1 2 3 ), ( 0 1 3 2 ), ( 3 0 1 2 ), and ( 3 2 1 0 ). A notational comment: mathematical permutations can be printed as 0-based or 1-based, and can list left-to-right or right-to-left. I will use 0-based, left-to-right notation throughout this article. There are n! (n factorial) total permutations of order n. For example, for a list of 5 items (or a mathematical permutation of order 5), there are 5! = 5 * 4 * 3 * 2 * 1 = 120 permutations. The total number of permutations increases quickly as the number of items increases. For a list of 64 items there are 64! = 64 * 63 * 62 * . . . * 1 = 126,886,932,100,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000 permutations approximately. The huge values of n! for even moderate sizes of n make permutation algorithms quite tricky. One of the staples of sophomore-level computer science classes is the problem of generating all possible permutations of a set of strings. A typical bad solution written using C# looks like the following code. Traditional Generation of All Permutations of a Set of Strings public static void Permute(string[] strings, int start, int finish) { if (start == finish) { for (int i = 0; i <= finish; ++i) { Console.Write(strings[i] + " " ); } Console.WriteLine(""); } else { for (int i = start; i <= finish; ++i) { string temp = strings[start]; strings[start] = strings[i]; strings[i] = temp; Permute(strings, start+1, finish); temp = strings[start]; strings[start] = strings[i]; strings[i] = temp; } } } // Permute() Why is this solution bad? After all, it works doesn't it? There are at least five reasons why this approach is weak. First, the solution uses recursion so the memory-use characteristics are not easily predictable. Second, it has an unnatural signature by requiring indexes (start and finish) as input parameters. Third, it does not easily generalize. Fourth, there is no easy way to generate a particular permutation without generating all permutations. And finally, I don't know about you, but to me it's not even obvious that the code works at all! Three fundamental problems when dealing with permutations are: How can I generate all permutations of a list? Given a particular permutation, what is the next permutation? What is the kth permutation of a list? I will present code that answers these three questions and fully explain the algorithms I use. You will be able to use the code as is, or you can extend the code into a full-fledged Permutation class as part of a high-quality general scientific library, or you can use the algorithms to create specialized methods based on permutations. The ability to understand and use permutations and their associated algorithms will be a valuable addition to your developer skills set. I will also show you how to use permutations to increase the security of systems using a technique called diffusion, and how you can use permutations to improve security testing of systems. A Permutation Class A mathematical permutation lends itself nicely to implementation as a class. For data members, we really only need an array of integers and a single-integer value representing the order of the permutation. The basic code is shown below that represents a Permutation object and a constructor to create an Identity permutation object along with code to represent it as a string. I decided to use C#, but you can easily adapt the .NET language of your choice. Permutation Class Definition public class Permutation { private int[] data = null; private int order = 0; public Permutation(int n) { this.data = new int[n]; for (int i = 0; i < n; ++i) { this.data[i] = i; } this.order = n; } public override string ToString() { System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append("( "); for (int i = 0; i < this.order; ++i) { sb.Append(this.data[i].ToString() + " " ); } sb.Append(")"); return sb.ToString(); } // ToString() // other methods } // class Permutation When we put this code into a class library (arbitrarily named GeneralScientific), we can call it from a .NET console application: Permutation p1 = new Permutation(5); Console.WriteLine("\nIdentity permutation of order 5 is:"); Console.WriteLine(p1.ToString()); The resulting output is shown in Figure 1.  INCLUDEPICTURE "http://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_01.gif" \* MERGEFORMATINET  Figure 1. Creating and displaying identity permutations This is not a very impressive start, but things will get more interesting quickly. When the Permutation constructor is invoked with Permutation p1 = new Permutation(5) We get an object in memory that can be represented as shown in Figure 2. The constructor code that creates an Identity permutation is as simple as it gets. The ToString() code that returns a string representation of a Permutation object uses the StringBuilder class, which is slightly more efficient than using string objects. Our representation conforms to the style normally used in math texts.  INCLUDEPICTURE "http://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_02.gif" \* MERGEFORMATINET  Figure 2. Permutation memory representation Because the valid values of a mathematical permutation of order n are 0.. n-1, we could have declared the data array as an array of unsigned integers. Also note that order field is synonymous with the data.Length property, so we could have left it out altogether. Deciding whether or not to include the order field and deciding whether to use int or uint are typical clarity-versus-efficiency design choices that must be confronted when using object-oriented programming. Because the data array has conceptual meaning only as a whole, I did not name the array "Items", as is usual for collection classes. It is very useful to have a constructor that can create a Permutation object with a specified value. This leads to a validity check method, too. The following code will create a Permutation object from an array of integers and a method that checks if a Permutation object is valid. Permutation Construction from Integer Array public Permutation(int[] a) { this.data = new int[a.Length]; a.CopyTo(this.data, 0); this.order = a.Length; } public bool IsValid() { if (this.data.Length != this.order) return false; bool[] checks = new bool[this.data.Length]; for (int i = 0; i < this.order; ++i) { if (this.data[i] < 0 || this.data[i] >= this.order) return false; // value out of range if (checks[this.data[i]] == true) return false; // duplicate value checks[this.data[i]] = true; } return true; } // IsValid() We can call and demonstrate the code like so: Permutation p2 = new Permutation(new int[] { 2, 0, 3, 1 }); Console.WriteLine("\nPermutation from array [ 2, 0, 3, 1 ] is:"); Console.WriteLine( (p2.IsValid() ? p2.ToString() : "Invalid") ); int[] arr = new int[] { 2, 0, 4, 1 }; Permutation p3 = new Permutation(arr); Console.WriteLine("\nPermutation from array [ 2, 0, 4, 1 ] is:"); Console.WriteLine( (p3.IsValid() ? p3.ToString() : "Invalid") ); The corresponding output is shown in Figure 3. The constructor code that initializes a Permutation object from an int[] array is easy, and we even save a line of code by using the CopyTo() method instead of assigning values in a for loop.  INCLUDEPICTURE "http://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_03.gif" \* MERGEFORMATINET  Figure 3. Permutation constructed from array test Checking if a Permutation object is valid or not can be done in several ways. There are two main things to check for. First, all the values in the this.data[] array must be in the range 0..n-1, where n is the size of the array. Second, there can be no duplicate values. I could have sorted the this.data[] array and then iterated through, checking that the first cell had 0 and each successor cell was 1 greater. But this does more work than is necessary, so instead I used an auxiliary array of Booleans as a kind of minimal hash table to keep track of which values are in the data[] array. More difficult than the validity algorithm itself is the decision on how to structure validity checking. Implementing a public IsValid() method as I did places the burden of validity checking on the calling program. A more robust strategy would be to create a custom Exception that deals with invalid Permutation objects. The kth Permutation of Order n The heart of the Permutation class is a constructor that creates the kth permutation of order n. This is a problem that is easy to state but very hard to answer. What does it mean when we say the kth permutation? For example, the 0th permutation of order 6 is ( 0 1 2 3 4 5 ) and the 4th permutation is ( 0 1 2 5 3 4 ). There are a variety of ways that a set of permutations can be ordered. The most usual way is lexicographic ordering, sometimes called dictionary order. The easiest way to explain lexicographic ordering is with an example. The set of all permutations of order 3 in lexicographic order is: ( 0 1 2 ) ( 0 2 1 ) ( 1 0 2 ) ( 1 2 0 ) ( 2 0 1 ) ( 2 1 0 ) For mathematical permutations, if each permutation is interpreted as an ordinary number in base 10, they are arranged in order from smallest to largest in magnitude. For the permutations above, the 0th (and first) permutation is ( 0 1 2 ) and the 5th (and last) permutation is ( 2 1 0 ). Writing a method that returns the kth permutation of order n using "obvious" means is surprisingly difficult. However, I discovered a little-known algorithm dating back to the late 1800s that leads to an astonishingly elegant and efficient solution. The essence of the algorithm is to take k, compute its "factoradic," and then use that to compute its permutation. You can think of a factoradic as an alternate representation of an integer. Let's consider the integer 859. It can be represented as (8 * 100) + (5 * 10) + (9 * 1) Or another way of looking at it is as based on a fixed radix (base) of powers of 10  INCLUDEPICTURE "http://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_equation1.gif" \* MERGEFORMATINET  The factoradic of an integer is its representation based on a variable base corresponding to the values of n factorial. It turns out that any integer can be uniquely represented in the form  INCLUDEPICTURE "http://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_equation2a.gif" \* MERGEFORMATINET  For example, the integer 859 can be represented as (1 * 1!) + (0 * 2!) + (3 * 3!) + (0 * 4!) + (1 * 5!) + (1 * 6!) = (1 * 1) + (3 * 6) + (1 * 120) + (1 * 720) So we can represent 859 in factoradic form as { 1 1 0 3 0 1 } where the right-most digit is the value of the 1!s. It will be useful for us to append a trailing 0 onto the right end of all factoradics so we get { 1 1 0 3 0 1 0 } as the final form. Furthermore, it turns out that there is a one-to-one mapping between the factoradic of an integer k and the kth permutation of order n, meaning that each factoradic uniquely determines a permutation. To illustrate this, Table 1 shows the values of k, the factoradic of k, and the kth permutation for order 4. Table 1. Factoradic and Permutations of Order 4 kfactoradic(k)permutation(k)0{ 0 0 0 0 }( 0 1 2 3 )1{ 0 0 1 0 }( 0 1 3 2 )2{ 0 1 0 0 }( 0 2 1 3 )3{ 0 1 1 0 }( 0 2 3 1 )4{ 0 2 0 0 }( 0 3 1 2 )5{ 0 2 1 0 }( 0 3 2 1 )6{ 1 0 0 0 }( 1 0 2 3 )7{ 1 0 1 0 }( 1 0 3 2 )8{ 1 1 0 0 }( 1 2 0 3 )9{ 1 1 1 0 }( 1 2 3 0 )10{ 1 2 0 0 }( 1 3 0 2 )11{ 1 2 1 0 }( 1 3 2 0 )12{ 2 0 0 0 }( 2 0 1 3 )13{ 2 0 1 0 }( 2 0 3 1 )14{ 2 1 0 0 }( 2 1 0 3 )15{ 2 1 1 0 }( 2 1 3 0 )16{ 2 2 0 0 }( 2 3 0 1 )17{ 2 2 1 0 }( 2 3 1 0 )18{ 3 0 0 0 }( 3 0 1 2 )19{ 3 0 1 0 }( 3 0 2 1 )20{ 3 1 0 0 }( 3 1 0 2 )21{ 3 1 1 0 }( 3 1 2 0 )22{ 3 2 0 0 }( 3 2 0 1 )23{ 3 2 1 0 }( 3 2 1 0 )For k = 5, the factoradic is { 0 2 1 0 } = (0 * 3!) + (2 * 2!) + (1 * 1!) + 0 The 5th permutation of order 4 is ( 0 3 2 1 ). The clever and efficient way to derive the kth permutation of order n is to first find the factoradic of k and then to generate the corresponding permutation from the factoradic. I implemented these two steps in a constructor Permutation(int n, int k) that creates the kth permutation object of order n. This code is listed in the  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutatations_kth" \t "_self" Constructing the kth Permutation section. We can demonstrate the constructor using Permutation p4 = new Permutation(4, 5); Console.WriteLine("\nThe 5th permutation of order 4 is:"); Console.WriteLine(p4.ToString()); p4 = new Permutation(10, 999999); Console.WriteLine("\nThe 999,999th permutation of order 10 is:"); Console.WriteLine(p4.ToString()); The resulting output is shown in Figure 4. Constructing the kth Permutation public Permutation(int n, int k) { this.data = new int[n]; this.order = this.data.Length; // Step #1 - Find factoradic of k int[] factoradic = new int[n]; for (int j = 1; j <= n; ++j) { factoradic[n-j] = k % j; k /= j; } // Step #2 - Convert factoradic to permuatation int[] temp = new int[n]; for (int i = 0; i < n; ++i) { temp[i] = ++factoradic[i]; } this.data[n-1] = 1; // right-most element is set to 1. for (int i = n-2; i >= 0; --i) { this.data[i] = temp[i]; for (int j = i+1; j < n; ++j) { if (this.data[j] >= this.data[i]) ++this.data[j]; } } for (int i = 0; i < n; ++i) // put in 0-based form { --this.data[i]; } } // Permutation(n,k)  INCLUDEPICTURE "http://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_04.gif" \* MERGEFORMATINET  Figure 4. kth permutation of order n test Computing the factoradic of an integer is very much like determining a fixed base representation. After creating an int[] array to hold the factoradic, the loop for (int j = 1; j <= n; ++j) { factoradic[n-j] = k % j; k /= j; } does all the work. On each pass, the remainder is calculated using the modulus (%) operator and stored in the right-most available cell (n-j) of the array. Then k is reduced by division (k /= j); in effect changing the base for the next pass by doing a reverse factorial calculation. The trickiest part of the algorithm is the computation of the permutation that corresponds to the factoradic. Let's look at how the algorithm converts the factoradic { 1 2 3 2 1 1 0 } into its corresponding permutation. We first create a temp[] array and copy into it the factoradic values incremented by 1: [ 2 3 4 3 2 2 1 ] We seed the right-most cell of the result data[] array with 1: [ ? ? ? ? ? ? 1 ] Now starting with the second value from the right-most value (we skip over the right-most because it will always be 1 since it came from the padded 0 value), we add it to the data[] array: [ ? ? ? ? ? 2 1 ] Now we scan through all the values to the right of the new value and increment by 1 all values that are greater than or equal to the new value. Continuing this process generates: [ ? ? ? ? 2 3 1 ] [ ? ? ? 3 2 4 1 ] [ ? ? 4 3 2 5 1 ] [ ? 3 5 4 2 6 1 ] [ 2 4 6 5 3 7 1 ] Last we traverse the data[] array and decrement all values by 1 to put the resulting permutation in 0-based form: ( 1 3 5 4 2 6 0 ) To summarize, if we want to generate the kth permutation of order n, first we compute the factoradic of k, and then use that result to compute the corresponding permutation. In the example above, we started with k = 1,047 and then computed its factoradic = { 1 2 3 2 1 1 0 } and then computed the permutation ( 1 3 5 4 2 6 0 ). So the 1047th permutation of order 7 is ( 1 3 5 4 2 6 0 ). The Successor of a Given Permutation A key method when using permutations is one that returns the successor permutation of a given permutation in lexicographic order. I implemented a Successor() method shown in the  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutations_successor" \t "_self" Permutation Successor() Method section. We can demonstrate its use with: Permutation p5 = new Permutation(new int[] {2,1,3,5,4,0}); Console.WriteLine("\nThe successor to ( 2 1 3 5 4 0 ) is"); Console.WriteLine(p5.Successor().ToString()); p5 = new Permutation(3); Console.WriteLine("\nAll permutations of order 3 are:"); Console.WriteLine(p5.ToString()); while ( (p5 = p5.Successor()) != null ) Console.WriteLine(p5.ToString()); The resulting output is shown below. Notice that the ability to generate the lexicographic successor of a given permutation gives us an easy way to generate all permutations. Permutation Successor() Method public Permutation Successor() { Permutation result = new Permutation(this.order); int left, right; for (int k = 0; k < result.order; ++k) // Step #0 - copy current data into result { result.data[k] = this.data[k]; } left = result.order - 2; // Step #1 - Find left value while ((result.data[left] > result.data[left+1]) && (left >= 1)) { --left; } if ((left == 0) && (this.data[left] > this.data[left+1])) return null; right = result.order - 1; // Step #2 - find right; first value > left while (result.data[left] > result.data[right]) { --right; } int temp = result.data[left]; // Step #3 - swap [left] and [right] result.data[left] = result.data[right]; result.data[right] = temp; int i = left + 1; // Step #4 - order the tail int j = result.order - 1; while (i < j) { temp = result.data[i]; result.data[i++] = result.data[j]; result.data[j--] = temp; } return result; } // Successor()  INCLUDEPICTURE "http://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_05.gif" \* MERGEFORMATINET  Figure 5. Permutation successor test The algorithm I used to generate the successor is straightforward even if it isn't as elegant as the kth permutation code. Essentially we locate two values to swap, swap them, and then shuffle the tail that is to the right of the swap position. The only tricks involve finding the two swap positions that I've called "left" and "right" in the code. I'll demonstrate how the algorithm finds the successor to ( 2 1 3 5 4 0 ). To find position "left," we start with an index at the second value from the right and move left until the value at index+1 is greater than that at index. In this example "left" stops when it points to the 3 in the permutation. To find position "right," we start with an index at the right-most value and move left until we find a value that is greater that that pointed to by "left." In this example, "right" stops when it points to the 4. Now we swap getting an intermediate result of ( 2 1 4 5 3 0 ) Finally we perform a shuffle of the values between "left" and the right-end to get the successor permutation: ( 2 1 4 0 3 5 ) The Successor() method returns null when applied to the last permutation of a particular order. Although I could have checked to see if the permutation is in the form ( n-1 n-2 . . . 0 ), it is easier to observe that this state will occur when index "left" walks all the way down to the data element at index 0. There are many well-known algorithms that return the lexicographic successor of a permutation, and the one I used is nothing new except in the details. An alternative that merits investigation is to take the given permutation, reverse compute its factoradic, reverse compute the corresponding k from the factoradic, add 1 to k, compute the factoradic of k+1, and then compute the corresponding permutation. This approach would have the advantage of making the implementation of a Predecessor() method symmetric and easy. Block Ciphers Now that we have the foundations of a Permutation class, I will show you some applications centered on security. Block ciphers are encryption schemes, such that the encryption of every plaintext block is a ciphertext block of the same length. A highly influential example of a block cipher is the Data Encryption Standard (DES). The Data Encryption Standard (DES) was approved as a Federal Information Processing Standard (FIPS) in 1977. Although DES has been recently replaced by the Advanced Encryption Standard (AES), DES will be around for many years. An advantage of block ciphers over other techniques is that, because the plaintext and ciphertext blocks are the same size, block ciphers are efficient in terms of communication bandwidth, and they integrate easily into existing software protocols and hardware components. The two primary techniques of encrypting a block of information are substitution  replacing a symbol with another  and permutation. In security literature, substitution and permutation are sometimes called confusion and diffusion, respectively. Although neither technique works well alone, together they form the backbone of modern cryptosystems. Let's look at how we can permute, or diffuse, a block of bits. I wrote ApplyTo() and Inverse() methods as shown in the following code. Some sample code that calls them is shown under the  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutations_applying" \t "_self" Applying a Permutation section and the resulting output is shown in Figure 6. ApplyTo() and Inverse() Methods public object[] ApplyTo(object[] arr) { if (arr.Length != this.order) return null; object[] result = new object[arr.Length]; for (int i = 0; i < result.Length; ++i) { result[i] = arr[this.data[i]]; } return result; } // ApplyTo() public Permutation Inverse() { int[] inverse = new int[this.order]; for (int i = 0; i < inverse.Length; ++i) { inverse[this.data[i]] = i; } return new Permutation(inverse); } // Inverse() Applying a Permutation Permutation p6 = new Permutation(8, 1395); Console.WriteLine("\nThe permutation is:"); Console.WriteLine(p6.ToString()); object[] bits = new object[] { "1", "0", "1", "0", "1", "0", "1", "0" }; Console.WriteLine("\nBits before permutation:"); for (int i = 0; i < 8; ++i) { Console.Write(bits[i].ToString()); } Console.WriteLine(""); bits = p6.ApplyTo(bits); Console.WriteLine("\nBits after permutation:"); for (int i = 0; i < 8; ++i) { Console.Write(bits[i].ToString()); } Console.WriteLine(""); bits = p6.Inverse().ApplyTo(bits); Console.WriteLine("\nBits after inverting the permutation:"); for (int i = 0; i < 8; ++i) { Console.Write(bits[i].ToString()); } Console.WriteLine("");  INCLUDEPICTURE "http://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_06.gif" \* MERGEFORMATINET  Figure 6. Applying a permutation test The ApplyTo() method showcases one of the many advantages of the .NET Framework by allowing us to write one method that can handle an array of anything instead of having to resort to templates or multiple overloading. ApplyTo() effectively rearranges the objects in its input parameter array according to the values in the Permutation object. In the example above, the bit array is simulated using strings as { 1 0 1 0 1 0 1 0 } [ 0 1 2 3 4 5 6 7 ] The permutation is ( 0 2 7 5 1 4 6 3 ) [ 0 1 2 3 4 5 6 7 ] where I've put the indexes below the bit array and permutation atoms. We've been thinking of mathematical permutations as an ordered set of integers, but they can also be interpreted as rearrangement instructions. When thought of in this way, it is usual to put the indexes below the permutation atoms. ApplyTo() interprets the permutation as instructions to "put what is in cell 0 of the bits into cell 0 of the result, put what is in cell 2 of the bits into cell 1 of the result, put what is in cell 7 of the bits into cell 2 of the results," and so forth. The Inverse() method returns a Permutation object that will undo any rearrangements indicated by the original Permutation. Performing rudimentary plaintext block cipher diffusion will by no means provide your code with security in any formal sense, but permutations are an excellent way to add obfuscation to your systems. Permutations can be applied anywhere from the bit level all the way up to the string level. For example, in any of my applications that have information that travels via HTTP, I always add permutation of the information to remove the "low-hanging fruit," so to speak. Permutation will not defeat a determined attempt to reveal data, but it will often persuade the attacker to look for easier pickings. It is possible to greatly increase the effectiveness of block cipher permutation schemes by adding rotations. A rotation of a permutation is the original permutation, but with all atoms rotated to the right (or left). For example, if p = ( 3 1 0 2 ), its right rotation is ( 2 3 1 0 ). Instead of applying the same permutation to each block of plaintext, you can apply successive rotations to each block of plaintext in the input. Again, this will not create a truly secure system, but will help guard against rudimentary attacks. I will leave it to you to implement a Rotated() method. Programmatic Generation of Test Cases Another security-related area where permutations are useful is programmatic generation of test cases. We've all seen examples of security flaws in systems that might have been found with more thorough testing. Even when the testing effort uses test automation, most of the time the test cases themselves are manually created. This introduces a practical limit on the number of test cases that a system can be exposed to. One solution to this problem is to supplement manually created test cases for test automation with programmatically generated test cases. For example, I remember working on a system that accepted multiple words as input. The input string could consist of an arbitrarily large number of words. After I created the test automation, I then spent months generating test cases manually. It was painful. A more efficient strategy would have been to supplement the test cases with programmatically generated permutations of the input words. Let's suppose that some system accepts a string of the four color words "aqua," "blue," "cyan," and "darkgreen" separated by white space as input. For example, "cyan blue darkgreen aqua." Let's suppose that the system compares the first and third words and returns the lower word alphabetically unless the fourth word is "blue," in which case the correct return value is "darkgreen." A manual generation of the 4! = 24 test cases in a flat text file might look something like: 000001:aqua:blue:cyan:darkgreen:aqua 000002:aqua:blue:darkgreen:cyan:aqua 000003:aqua:cyan:blue:darkgreen:aqua 000004:aqua:cyan:darkgreen:blue:darkgreen etc. The first field separated by the ':' character is a test case ID, the next four fields are the inputs, and the last field is the expected result. Even with this artificially simple example, it would not be pleasant to manually create the test case input. The following code shows how we can use Permutation objects to easily generate a file of test case information programmatically. The output from running the code is shown in the  HYPERLINK "http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/" \l "permutations_generate" \t "_self" Automatically Generated Test Case Data section. Code to Programmatically Generate Test Cases Console.WriteLine("\nCreating file testcases.txt"); FileStream fs = new FileStream("testcases.txt", FileMode.Create); StreamWriter sw = new StreamWriter(fs); int id = 1; object[] colors = new object[] { "aqua", "blue", "cyan", "darkgreen" }; object[] casedata = new object[colors.Length]; Permutation p7 = new Permutation(colors.Length); while ( p7 != null ) { sw.Write(id++.ToString().PadLeft(6, '0') + ":"); casedata = p7.ApplyTo(colors); sw.Write(casedata[0].ToString() + ":" + casedata[1].ToString() + ":"); sw.Write(casedata[2].ToString() + ":" + casedata[3].ToString() + ":"); if (casedata[3].ToString() == "blue") sw.WriteLine("darkgreen"); else if ( casedata[0].ToString().CompareTo(casedata[2].ToString()) < 0 ) sw.WriteLine(casedata[0].ToString()); else sw.WriteLine(casedata[2].ToString()); p7 = p7.Successor(); } sw.Flush(); sw.Close(); fs.Close(); Automatically Generated Test Case Data 000001:aqua:blue:cyan:darkgreen:aqua 000002:aqua:blue:darkgreen:cyan:aqua 000003:aqua:cyan:blue:darkgreen:aqua 000004:aqua:cyan:darkgreen:blue:darkgreen 000005:aqua:darkgreen:blue:cyan:aqua 000006:aqua:darkgreen:cyan:blue:darkgreen 000007:blue:aqua:cyan:darkgreen:blue 000008:blue:aqua:darkgreen:cyan:blue 000009:blue:cyan:aqua:darkgreen:aqua 000010:blue:cyan:darkgreen:aqua:blue 000011:blue:darkgreen:aqua:cyan:aqua 000012:blue:darkgreen:cyan:aqua:blue 000013:cyan:aqua:blue:darkgreen:blue 000014:cyan:aqua:darkgreen:blue:darkgreen 000015:cyan:blue:aqua:darkgreen:aqua 000016:cyan:blue:darkgreen:aqua:cyan 000017:cyan:darkgreen:aqua:blue:darkgreen 000018:cyan:darkgreen:blue:aqua:blue 000019:darkgreen:aqua:blue:cyan:blue 000020:darkgreen:aqua:cyan:blue:darkgreen 000021:darkgreen:blue:aqua:cyan:aqua 000022:darkgreen:blue:cyan:aqua:cyan 000023:darkgreen:cyan:aqua:blue:darkgreen 000024:darkgreen:cyan:blue:aqua:blue The code that generates test cases is straightforward. An identity permutation of the appropriate order is created. The while loop iterates through all possible permutations by calling the Successor() method and checking for null to indicate when finished. The ApplyTo() method generates the correct permutation of inputs in lexicographic order. Then we apply some logic to determine the expected result and write to a file. In a realistic example, you would likely write the test case data to a SQL database or an XML file, of course. And the determination of the expected result would certainly be the most time-consuming task you face. Programmatic generation of test cases is not always feasible, but the ability to use this technique can increase the security of your system by greatly increasing the test coverage. Random Permutations A problem that is closely related to programmatic generation of test cases is the generation of random test cases. This is useful when creating all possible permutations is not practical. Within the context of a Permutation object, if we can generate a random permutation, then we can apply it to an input set to get a random test case. An easy way to do this is to combine the Permutation constructor that creates the kth permutation of order n with the System.Math.Random class. Suppose for example we wish to generate a random permutation of the set { "ant", "bear", "cat", "duck" }. It is simple to generate a random permutation of the set like this: object[] animals = new object[] { "ant", "bear", "cat", "duck" }; int maxValue = Methods.Factorial(animals.Length) - 1; System.Random r = new System.Random(0); Permutation p8 = new Permutation(animals.Length, r.Next(maxValue)); animals = p8.ApplyTo(animals); foreach (object o in animals) Console.Write(o.ToString() + " " ); Console.WriteLine(""); The Permutation constructor that creates the kth permutation of order n needs to know the order and a value for k. The order is just the number of items in the set to permute; in this case, the animals.Length property equals 4. Because there are a total of n! permutations for a list of n items, we compute the value of (animals.Length)! and then subtract 1 because we are 0-based. In this case, we get 4! - 1 = 23 and assign it to a variable maxValue. A System.Random object is constructed using an arbitrary seed of 0, and then we generate a random integer between 0 and maxValue by invoking the Random.Next() method. This generates one of the 24 possible permutations of order 4 randomly, which is applied to the animals[] array using the ApplyTo() method. The technique just described is fairly standard in the literature for mathematical permutations, but has a pragmatic limitation. Notice that the technique requires the calculation of n! as a preliminary step. For the C# data type int, the largest value is only +2,147,483,648, so a Factorial() method that returns an int can only calculate up to 12! because 13! is greater than int.MaxValue. Even using data type ulong will only allow a maximum value of 20!, or in other words, the permutation of at most 20 items. An alternate technique to generate random permutations of more than 20 items is to generate an identity permutation of order n and then repeatedly select 2 indexes between 0 and n-1 and swap the values at those indexes. This would not necessarily generate a random permutation in the mathematical sense, but it would generate a shuffled permutation that would be suitable for many security-testing purposes. Conclusion In this article, I present the algorithms and code for a basic Permutation class. Permutations are the backbone of all modern cryptosystems and I demonstrate a few ways that you can use them to increase the security of your code and enhance the security-related testing of your system. Although the code in this article is usable as is, you could extend it into a full-fledged Permutation class by adding error handling and custom Exceptions and other methods such as a Permutation.ComposeWith(Permutation p) that returns the composition of two permutations. The .NET development environment is still young, and it does not yet have large scientific libraries. Security is no longer an afterthought of the development process. By incorporating security from the earliest stages of product design, you can avoid recurring security nightmares after product release. The ability to understand and use permutations is an easy and effective way to increase the security of your systems. Related Articles  HYPERLINK "http://msdn.microsoft.com/msdnmag/issues/02/09/SecurityTips/default.aspx" Defend Your Code with Top Ten Security Tips Every Developer Must Know  HYPERLINK "http://msdn.microsoft.com/msdnmag/issues/02/06/crypto/crypto.asp" Protect Private Data with the Cryptography Namespaces of the .NET Framework Background Information "Permutation Generation Methods," Sedgewick, Robert. Computing Surveys, Volume 9, Number 2, June 1977. "Standing the Test of Time: The Data Encrytion Standard," Landau, Susan. Notices of the ACM, March 2000. About the Author Dr. James McCaffrey works for Volt Information Sciences, Inc., where he manages technical training for software engineers working at the Redmond, Washington campus of Microsoft. He has worked on several Microsoft products including Internet Explorer and MSN Search. James can be reached at  HYPERLINK "mailto:jmccaffrey@volt.com" jmccaffrey@volt.com. Acknowledgment I am grateful to Dr. Peter Cameron of Queen Mary, University of London for suggesting that the factoradic of a number can be use to generate the kth permutation of order n, and to Dr. Kurt Bryan of Rose-Hulman Institute of Technology for reviewing the mathematics in this article. qrs}+,89:;S T r s t u     . / T U V W n o y z { ӱӱӱӱӱӱӱӱӱӱӱӱӱӱӱӱӝB*CJOJQJaJph 0JCJaJ"jB*CJOJQJUaJph5B*CJOJQJ\aJphB*CJOJQJaJphB*CJaJpho( 0JOJQJjU jU>EQ}{ e+Ig7 %&RS7INSYK!!V"""""""",###C$K$u$$$$$$b%c%%%򮜮"jB*CJOJQJUaJph"jB*CJOJQJUaJphB*CJOJQJaJph5B*CJOJQJ\aJph B*ph6B*CJOJQJ]aJphB*CJOJQJaJph87;TZ$Jo$%7^ 5 *+LRp  L c  & Fd[$^c !!!/!0!K!!!2"V"""-###b%%&_(y)))%%%%&B&C&K&M&&&Y'\'`'d'(())\)g))++---. .I.Q.z.}........*/9/D///////Q0\0m1s11222222ϿϯϯϿϿϿϿϿϿϪϪϿϿϿϿܘϿϿϿϯϯϿϿϿϿϿ"jVQB*CJOJQJUaJph B*ph6B*CJOJQJ]aJph5B*CJOJQJ\aJphB*CJOJQJaJph"jB*CJOJQJUaJph"j%B*CJOJQJUaJph;)))****3*5*[*m*n*****+-+.+T+|+}+++++++5,y,y,,,,-R--..+/{1223=5G5Q5[5e5o5y568889{9:::22222222!3$3:3;33366667799w9x9y9z999::;:::::<<<<<<E=F=Z=[=e=h=====յյյյյյգգյգգյյյյյյ"j{B*CJOJQJUaJph"jxB*CJOJQJUaJph"jB*CJOJQJUaJph6B*CJOJQJ]aJph5B*CJOJQJ\aJphB*CJOJQJaJph6B*CJOJQJ]aJphB*CJOJQJaJph1::V;M<=========ll$$IfKF$ ,L 6    4Ka$If ==================>>> > >>>!>">#>$>%>0>1><>=>>>?>@>K>L>W>X>Y>Z>[>f>g>r>s>t>u>v>>>>>>>>>>>>>>>>>>>>>>>ɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸɸ!B*CJOJPJQJ^JaJphB*CJOJQJaJphCJaJ5B*CJOJQJ\aJph'5B*CJOJPJQJ\^JaJphH====>> >>">#>%>1>=>>>@>L>X>Y>[>lllll$IfW$$IfKF$ ,L6    4Ka[>g>s>t>v>>>>>>>>>>>>>>>llllW$$IfKF$ ,L6    4Ka$If>>>>>>>>>>>>>> ? ??????&?'?2?3?4?6?7?B?C?N?O?P?R?S?^?_?j?k?l?n?o?z?{??????????????????????????????????@@@@@@@"@#@.@/@CJaJB*CJOJQJaJph!B*CJOJPJQJ^JaJphW>>>>>>> ????'?3?4?7?C?O?P?S?ppppp$IfW$$IfKF$ ,L6    4KaS?_?k?l?o?{??????????????ppppW$$IfKF$ ,L6    4Ka$If???????@@@@#@/@0@3@?@K@L@O@ppppp$IfW$$IfKF$ ,L6    4Ka/@0@2@3@>@?@J@K@L@N@O@Z@[@f@g@h@l@m@AA+A,APAQAAAAABB2B3BBBBB C"D^DaDnDbGcGGGGGGG"jB*CJOJQJUaJph B*ph 0JCJaJ"jB*CJOJQJUaJph5B*CJOJQJ\aJph6B*CJOJQJ]aJph!B*CJOJPJQJ^JaJphB*CJOJQJaJphCJaJ0O@[@g@h@@@@A C5CrCCCC"DMDnDDDW$$IfKF$ ,L6    4Ka$IfDDDDDEE=EAE^EjEnEuEEEEEEFF FCFDFeFiFFFFFFFFFF.G2GFGJGKGbGGHHHHHHH JAKSKKKbLtLM'M9MKMGGGGGtHyHHHAIBIzI}IIIIIJK}KKTLZLMM.N1NGNHNmNnNNNOO?PJP_P`PPPQQ2QRvSWW/X0X1X2XϺϺϺϺϺϺϺϭϛϛʛϛ"jЫB*CJOJQJUaJph 0JCJaJ"jB*CJOJQJUaJphB*CJOJQJaJph6B*CJOJQJ]aJph B*phB*CJOJQJaJph5B*CJOJQJ\aJph%56B*CJOJQJ\]aJph3KM]MoMMMNOO2QoQQQQQ4RXRRRWSvSSSSSSSGTMTsTsTyTTTU UUU[UpUqUUUUV VVZVVVVVVWW&W,WIWrWWWWWWW3XXXMY[[e\u\]__ aac]fgh7h;h]hphqhhhh2X3XWXXXy\\^^^^________ffffgggggghjjmmvmwmxmymzmmmmznnnnppqqqq:rEruuvvv򳬳򳕳"jB*CJOJQJUaJph B*ph 0JCJaJ"jB*CJOJQJUaJphB*CJOJQJaJph6B*CJOJQJ]aJph5B*CJOJQJ\aJphB*CJOJQJaJph:hhhhi"i#iBiFioiviiiiiiijjLjzjjjjjkd@QR?@Мќ⸦⦟⦟⦟o( 0JCJaJ"jB*CJOJQJUaJphB*CJOJQJaJphB*CJOJQJaJph6B*CJOJQJ]aJphB*CJOJQJaJph5B*CJOJQJ\aJph2œ]h@Q t01h2P. A!7"7#7$7%S DyK chttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutations.aspyK http://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutations.asp#Dd  S Ahttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_01.gifb!qpU`x|2'G!En!qpU`x|2'GPNG  IHDRSOMPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fDbPtRNS%bbKGDH cmPPJCmp0712Hs,IDATx^]vȺ= 'u; =}wN엀hHI:@4/bݽW%v[K*T[*_Y3כ<椳7z+KtnIM5جLYAtPy͡}e`\fpo{wpzCҿ=Gw_p;RЯP!qW;m'L Nʣ '/.>,K͡R;)2p4:6eZ3܄ooIӜqi *'DP#/lj0b.bq@zҫ;AZZ>" :Ov.!& h}t(X9Si?==@8&@+$k8>ה| 01g9I`uF8&lm)J\Xf_``TG 2 *pj,(qn9 3)EEGd#9ǥ$( PdX=|?8FCIDpKI I|襥#8F U@yyFi ;BIS8'`D(%%$KPK$ |E+_  !ZWfyI|`r< ɛ8G )g`a! /^Fz=1?R Pt'?OfkbFQ;W  -w2hl=#xn%: YVifсf|a oTn/rk_#Lx:sfJI D@Ҵ9^))c&c(8qZnr?$悦8E+0rY:qe&]Y,EF.vO 7v`J1$|e:ZIŽLYaqD4&Z^^|Lmv۶($5pޘ#‰fMM2I+8.OSMvE克eZȰKN Gc%#7RFfG4C>mKj6+ \8-Ф.yN\:"MKE9cN\i#d !A@7b`TvFMg2AG`ܚpp.uY-Fe9YCaOmFO$sd@6y" FAn7:%Q  ȉÓ ; ToC"y~]%r1))(--di3\Q0|4L`$3b [XLAY iD478=t*ݎ|{pj( ^\0pB]<+8 LJ6)zXWp`Y "[@_N#tXHG /&FðK|0\dB|E*/U_2$7" P|[م)9hRo!>I0YBQc33ėYo7tɿfU[H=6 ?Ih$d% ap/,>#}هjCD1X?f 2iT (gQ/θ\OoC,h0sDN̏%"YT9s&Y"rE)7ɠqbN(*ˏ\t gY2g6Jf1M'$͐?~NGl4N&(ehk .rbR=b΂riC?R|c<`i : X2g" F O3 "f1L/G1yj41D|릘 =7晈+G $&B2'GЌaTm@zr_ÇEI jkvu۟v `ЎVߺjs[W9نV%d"C :dt'F  R2Q24:f3d;Ǥ#%AEC r)8ŕ R3$z$N QH!b<9oZ†ftX|&`j>-쬭65HQF:Q~ĥ`=nlq-<}] =ƥdN)ʔZ:~] ;ha5-Xb$-˾Y#lh gENΈ՜4jO//^ja lc0;''ZfC1#jk B$eVs_\Ί4k 7f2V{\T^$FNL-,g80D.2>0~,C;wvRyY$zH4/pk[_ASshWo/Y!0bqx 8%Ԍ#d]' BGQ2ۈZtLx:MGTS1fK/Z!HP~PQ"t4 iOVEoГNFAJRvEtls藫Y&ݸO$~e W)#4ۈs#pl5}w +'mzݓ_jj65fnk/rQTƟ dP3mNTrGqiHmT@3w}|(%QYCtJ evwlM܈ʚ"z7CZwb1hXϞTݴK&lTfMݟ6kkeq$ } մ`[&4%i \׍^^q8F|5i2[؟RD/ Qn=1w_#jA?{yn#EjkDȫ ::4_}VUKGs7_=7NJ9Z p{yރ}Qp hs4E 52,_ՕJ=gr93?_l|>˗ ?QؤJtgxV˲p݀/v[ێ2/?dW|x'U*r_@9G󼋬v=@=f Td$g3O{ 3[_Ų|3[ @ ) ]n suG2TL;+OT{jԂAڝyewRx0BS!/ţC[EN{]$*N ɯ潌 &-C-L^d; g\t>_~_ ~X%{2oEYdBp RP+cC5T=J|hԁtU^' y~?DTzvnwSt|nQI;+&$Dv^2W wbUģR)_W`c <M耣I=@{Z t5pl|Gq?hi+p\Gq8m'v0jUwkDl#b=/i9 4tSMݟnĺtVI3ղUurCQY\'Mȫi,_޺^^P{袦O1N%`(1R{x@޵s%wǩ-Bì՞UOuGA;7ZI牗ǭW^sȏw! ¨rbƺLʻ0"uu1Y\^c髩jPr'};*ghK ;;P%)WN?âCjFr $~n2#. Ω^CqGlQ_]aS:CfVe2CvT5ykt鐡   Uz!qY!9dv]"j †.J*Ӌ} @-S{^BQ3Ķ6?>PuǢ2ׂ2+)/J= չ+*CqA5ầce+'C p*IɏcК+f(}Mj= ?ʭ{9𥪧Y>VB s_{oeM2nSɸ |KS/z}ef?Gι6uH&VY*'"`We.TuS*"'9zKzpJ{P!ڼc~xkc5K|wIO9w*ep٭ VT zw .\z xAuGxEaU(ѡ;w[{X9*Z31m?^jEn[P[N_&P{?|K[{̝';EZ+VY<׆YU%ߎ$ s=,); o쓎5$$,Hk=f?T=ͮWaˀq{P6=_wq~~Cqϫٓ9~*]//xn=oƉ9o}p= ?Ǎ^^K^wrOfU>fv~lYԧ9y3nwYr Ϊܼ"-[Rqq4+^yYɐW7+l;%9w[߫Y򝷅ô`DY&QDNA@xl=%V;L(^걗qQmqIt~=#o9Yx"G' QMMn;!ľxnwη_,;2zy =Uq#j +C9>\C8\y\EcP8){*]ADg~R Cܞ5o h6HN\R$H6E)CxFޑABY]-WA<`/dilH9}̛[q|Btq nd'nP=*:qUȜ]@Y%„SX*W%iZ@Jv{Y6|]߶y=Wxw1P.:? vH1zfĈUb8}:kxɇ{_qӐ?@T[0L-U3홿cxCwZ%&\!潼f隞?-K\%uzG*75wCrIۆqu /6zqx$T<ll!s&]wwJ0Nb[{{76AWy77TrS#ՋJx f@]9Iq*wNWShE%iˉDet=Xt̒h:ظmF4^l#.6N "FJ%d˸Ӑؠ\De. +j.\j{}[66߅kf 2I)]^jYopPogpVoTeqiz|D޴5`>ܥ\j{@CRsU.=X!w9r~*,琻9?xKms]j{ʥ 9.=G^Rۃrڞ#r}KmϑW`>ܥ\j{@CRsU.=X!w9r~*,琻9?xKmsȉ]j+jί־^ES|I~U;#gX񫍢MI0,a췭ηb_3)=hO6Ȑ b^7 d6,`*I>cȤR>1?#\#G\b5׻ջ}4;P6ȉF!"]$icDWALl5}cMW]FIϟ^+ *x;=.3J"z@N_OqG5<@ ] xٿX&p6Ntwjy_XF*8Y>k;;O"O9Վ rI>xw\g NjRe G) H3/E mڧ0{WȺKcо{\z1r2$EEhT\ŶcVf+b7U25ňx}aXSv5#ɤmrQI; K@Qc<9)g.: e=Jcxak8I)ٴ.ZgUlϢ!DYHcZ,Wo9"N5#X @.AFx^"Nm<_rgg5m{}1u&8:>{ BW4Ul16s?(\kh%jB@pqT}xI-7 y|Kz.+d$).t˶,+2o]SpuȾ,,\\:pSԚJ{Ǻ-ܞ 2<ƏWe+"5[LJe$;*dIcw~yb$/IY.is4h9rM,u6^Jߠ;,{#k,3cbq//?%AT ;!7ON~L2_9%  #de;fѿޟUm'VYvOVl.fCziȎW_U&k61DZ')&mnC⪈ȼ:Hs RסdY >{/oՂsy %T2qmidaFiW^rhC"e$MQ7Wڦ*fYIcn踨1 )>-|6'3#N|WV$T[~މjIgɎu0Ozx_s~y!5F΢lS Ϧ:UJ;c{dxvF=C9wx1 FھXg9+v:IBVY\rlB6$]]P9d\=M)FPhyDӟc9Yore_CީI欎V^>:qu'I2%-+yAW&?1ExVDdV-ϯi[H?_3&JG.Tn@l1J$ma'!e.I'ӽG1,)E?zI!rxD$!F=$BZ^Lh '-E'FnNhP|u6-Ws"3]Ș_$ݩTzJ;LJŹɋe"Lb|{-ya-=N&aS+} `J9e}"_,j/,oF}`C΋\-_EH ~Z!yl,N=H_1p~Nc~zvV_ԙ1&Tk45V-5zo¤eh|zrtԬq>/B0L/+שn#ֈo=I&5-ĝ?i*C4T%aˤڤ( /'}sjPEAZGCф[wNI#e2RF@>lhޘ=ӟi{d]ñJ]rUs IIZ6e<E\M5'HFb@O,ҸVzYg?OR*װ~S?˘om%q dT)i1jH퀬$3g.w%O/0L*t.|)oSvJIU#t1rOq74&.]*~ui,4_ 7xiQFFTX"M-ҶS\ zYGf8qd:3&y%Y\ e/~LemQ2鮾K x2$gtWn1,I/XWE( &!ed1<83Y#`bʟ!;bsr}Oz9׆3 mhyu oOαWFE(:8k{HhC'_^H+qq잴,h dIZAHS4mDlqQUF\D j; c%דh=!Bt=Rg tVwFǯ)R/^c>! #_3[d$Co g>X[)6u뽹s\*?EBY/lt!S(Ik^:IF1zZ|H5*\S*s \=*=ȋt /7 ~crcQg6^>/$0lD{qL{\mN9NzE_ʁLv|} c'xk.ۼHrg۱(T`-X6Ȉ9z}e%*xE6a^5\m}M3;l3Mw@QP>7cnIߊN[Xʼnz"z9%Z)uxy&@nb+ p~k. ?% +lJ]JEdR?nQxi ʇa, \wh mcZ_.b.;MI ٱǀFU1O~o#2.Y5bژs@ ̼m6Yd0,8EXGq.q@ WZn#-"s ;Q&B ۣ-'Y mjޢ :.BE-ɯB܌כw:Cr>.)րG#N.{.5:_xP|=]>jW9L1Lr{Md 4Ҩ65x3\11$n sx=R['+cFׂlA*Ԍ![͑cuH˯Dɓ`ѻ'}l/k+QH'kA֍(eF}bPVg]5EQhאmsq}ZI Rp6yqY]r;_x)k_jWys"ό|,09U t5۬0\g>7#Q ׃ޡeEgYg/ު(ep뎐 .-6"u!B򙸰z]VW}ɒ0Mb%X|wA]hpw.QFlԦkfݔC#+&7i^(Ed%1nlxNvLj蔹Lt&kTUI$"'#.-Վ6]+e=XĒBV ̺`9FѨh9gyE+BQj7׫߇k: dyv;Dz}ɲ@}u];\bs-Zu2w&x]0&kVIamՖAC'׽S d@9[^w/1WpK=Oejbɵ 6$鳲n 3`l1;-bǿI>&ھM{aŀ?Y!~5ԧkY$!o7iTaGyAᏢ˸ nwOMe^ЕثM$ſ3h‰lJzu-5$q u19Gl걻廢)$(uamLmڦ줢m¸7:v[Bܵ_į3֘x6lݜǛ&%J1=^L:IhҊMl1;IWZq=̬&2U !y:!QjA!H%Fe(8W 5&{Ƕ%Q5G0;C"P>\S.k^lr݈oJe TnBkWV薿Nc5 iEOȟYm3jN/\oHr8-g8IjS+X6-~_v* (4Uۂ0so_jY,0~ܹ@"T><등mN`)-19nYYbޮ=MAzV g6ҍڶ5F(^N[#eKx۔u1[\CD~B}wzR[-LkcMht@|[pZ9NυijMs'>sC?~vtER-e35qy7TU9@s^MUXHV.\#ɔD{u(oauX~ݫ9dj;vWNk^yk{5<iy\D˺W v"ʸo#}*AƢh{gBo7\/YXc8@G+~ڬ{}q/І.uPp̪3^;ɵǞ ;{I^KRĶw亚IدhX'VT3DS\rVX+z&Lxy- #|WǾba>lBjKuZڝƵ.@,c[D,;f~i2(E9jbiͮz_h,\fzVnj"uD"YRT;tayɞ v*1#5? ^Tm~}t{.։QeTz+51R?'dm2<ۈ⢟ș=M{uZW[zu[(޿N&b .7QznIj$+% bߏkZݎH˺U[f<*7&wq9\xL-Et {3i$<".Im,aʗ*jӣ(f\۳'IАvtdBCw_<.Y򗆗y >m&~ElbX:X'eݨ̺g^rbvY n)4"]٭٨-UْFž HU?ifz8 M\42l:S*ݜzt{dky`wοk=实i=Uu#ުgr' C(j$/3a9Nmz0'YrˤkO)#Ӌ⸶ifw*z;&3qrsg]O?. W{>'\7j)LEvH`a$ֵNW&.r\] yU.359x5Vh  Rh=KYI)nkqC P :tE'vh M.E( m뷚~ۗ;c%n%~zF{>z\oηg(("vu@VWn}Mz \= i"",cr&r%ncFdnwsPn!3]?=@< oN#WqEu6qemakXދj>]C3sd=p>Wk\A'J/6()74(utvnq8EWv* ͣT1^LhQCuk - ]ѥx3hR" uG/CrS6N0Fr3}XјQԻjP zѓK>tȦ[zBe HI [7`flx"x̮~*,jatdIiI;+ضꒄL#ܾH!"Ed P^s9yªÙvsAd|pݣVԱ;tԻuá.o8 rLQ;'h(}'z6_3Y!m{pLcw:˺:m!%&uEmϷE +S@C0XrUt8w8Y]D(3 'k³y>vI"Ԋ7rqꛯjMȡYVAP2N $n%jh>T|tQ3dGL_ƒe#'芬7o@t/p=l!DµHj/G G%pC¥KmRw]/_]IENDB`'Dd   S Ahttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_03.gifba&G )EvOLI=&Qn5&G )EvOLIPNG  IHDRJw`PLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fDbPtRNS%bbKGDH cmPPJCmp0712Hs"IDATx^]vHe#%d&kOH,0 D -%ԏtGdw} (t-PU j?Ys^ ,S[%.殀󥊋Ͷ+/NԞկ]THO.[Ґ[3,*-y+%oy9  ӳw= 'L1&Pv>;SP<#9IN݁%Ɇb Ev ^kCJb&AIy P¹),;@:H8W*)/\͗,tp#f1i򓠑nK0#@HA@7aE~0#̀ʙfbK֠G>Vξ0[o|a^P^\O7~ @5LJM%"YG 'A uB'>[$>`5y4U`E)8;lPf9F <<jXAX Rr3p Iu_- _G>3(~}0D9@!f:a >w3h.lY]e>M>u>\VPP>>Lcaа k'+4PW+JL-UQV^w ~djEUQKHq6|Dsh{M/;Qj))؅i=qzʾd_ 4զqNR^Uv℧aGӄ,)>D44BX;\ GW)B.(?:iǤm\DryN8 ǝ7vC:BDb}' ̉Q wOg0Vp f rf#^K;~`Hd3mx.x / =i] :&DR3JL)ȆDFN Bp7Q@{tx &I23Ki{Z&(5IΑJo ɎIz@>CGP{WmE5@z n!D!E$IA 1#L}KqF$vsL&JrAMKА4j'. j I "K xؙBɬ99E U8o83 "xPsw` 'H8h1,#N(ʊQ 9g"8<̀-`%&e+%TѪn>n@-d%zOƒuJF(q `]E as@B`ki+"ѣ䂤(̑Mn@3$"2)%Jiz*>lb L#v$\PuCR'V̾F QyO1K&1oJN!o+76%a#`fr#Y(cX( J|s1zo9)p.q=>P(# ܸROWplx j{;H',?D*GbVM,Sw? hn@ ’Y-N$* f%40o?&v θ,G(@.$i:8XlXS[P(G`Y((86:iWhD .1)K&CHHqn5&9Ɖ0 /LD>(&4`_Y v$-87$OI =:|@w(5sMG7"R':/hF}~ p!j1ayi{NMo<-8'#Tz ms7?oIK"G (G'Bb~t,K%&3U~;(*j1iqfR4俁kެԜxG ' B(!iI 6Ћ'`3\)Ӓ, %Gz( sK`|r x _go 9Z*"}aY/ K)9'xb!`nRP6RIl2(@y`Tň&!& 983MMX lKZ2b @s>nV@Iu%,@ * 0PH5 })eI`- %-PACa.]yFTd|lr i3LNQaz 1zלA0 )9ŝ*SZser$X' ajg$뀢QH{1Ftlu=Mxt:Pvm6ʦ( = A7=!@mbP|(WBeǠ2^ !|n4xSk9%f0b#ۢaTHr>LEt0-H »#zPl@(B0ML2e>q Hɦ єOr瀞JY(C4 -p)7_"uFpٿ0_zsٻ$|^:˫N\u.+q;8Ǧ8BV90gqK'J1'&Lj1P uk1P%HF]hAZ >n1@Fɐ Xvf".tiv )8 䚛t&€WМD v`:9t(D'ԊC`'Ԡ٠%f5>&`-AĤO9&_m=G- wNt1^ƋwGoOߝ ?霧e锜GG¯J˪^:^<9([srړg,GZ8'!Bh4ؖyM¢nf*5en˷?'&N4:$Yx)._sB[ xC8n;of^WuQ7:Hz@:Gpune;,`W(/#dgOC]FWb^~B ?c?Qz]zqx!cʀ* l<}.28~R!emD?QkՂCFG)[>1APza0⬄gcĹ$HQϵۄ"?"Uꖬ&/5bŏHz9Wybا j?YԲڋ^]YEs1:^2^i(pZ1&*(FOퟀ&ЎH#CGURϙqoN*Δ)Q9gc&.« VKi{pVL<,K7{ =j.g3&nYF`1 eO ^Zi+B䗃T c-xĶ6Y *Phsgr^ӟ-^0xgc?מlg5chn$׉2ef3쬮w{#`rgOi9 .نLb eg^'g&'9yAInfg];,eOZ=4N{,.8~+zg/"#Z( OW* 1a~qFtʎjzק҂Iu|Krˌ GvoTB+k/?i,ڟuGVB]֒*7K^}¸dߺ᪚U Y_qb+WͺkLȉsX`So\}ɘn&]Z~ )변S$\+{7i QUf(Uz$P,~i'Qnk\GV |6Ǔ@yO;状Ơ}G6vc T8#"}JwO" (ݵz=mʉKcCa >K,EŒs0y6!WWbU5j8oH*!Q}ԠG { 7Ge̾@y e&giOmI_9w!K*턾"ߩ\RyR똰Y@.JG2;Rk1ZCI]Ghr%iXqN\q `#xKa--!6jGe"PdZck)fI8rl #ݪ+MC>;$TMuTc)#Fu;xd=iV7 !,B۷52h x/rѾiș=Y(d34u]%ےJ.j+`PU/=/'#ſۘ-^Z:^'QiW+@zCWտUiK[#ȽuxsEe>q6f6yͲ4:؏dӾD(gΐPמ~1ӛmF-uC j=EG0knx͈% RUN,qk1|\y?=u=IZW[؏L1J\,ݞޯ}ZKOO7W#F>I,Pǹm&M_f%Z<8,YD9F{_oVvm^޴qUY{EǥU#VGH;CTUQnRZnh"}SW߉~ Tkm}=A<ϒ5=O+OGƩVhgNJm 0~lʃ %Nl Qoޅ䅥$X.dOz{zl)muxrͯ ъP;lTkk0g)59g:oW γfٴS '- -@q~8 {~d>G=B8׸9V82 eu7Q> ĂqUq` \q< zl&O0._19\B wky0*]emܲSju{x?d6qzq̱7 WZ'sB4nȹ[-rrqf(O]J˜^BܟWX0OʽWwb -pZ\ Fӗ7?Q5c0oP҆\^A6XX .,|63;a{eFրٔ~<10G&@me4Wgl lh9PJ1JhY E|Heq+OOU9ϹBi(h,Ehl|r2`gSr}V \x[5\$E55^z6%t.ca e:ӯi q[<(t;M׻ 66J\E+bp0׋l '2ԕZAK*~ĭˈJ^hQ!@Wjc\\vvRYu7B8r:#d.vXQeƮ*gOcE UbG.N.X^skb\si-9\W7 w+reyĶ!O,JRz_z5F-tzǷ,KXٕ%cx\{e(5HŒ]PLrY?+F@֬z?ř% U{x\~!6Q`Q? ^ nnXol>C)>׉2=su?ߠgoxg ҥc,dA罞6h6I#jr2f|5k*BK[9ƹBiGn*|P#xh @f6#ǹ,| 46ZP@n륷R t-xEܲWP9h#NO}V03PlP %GcYs E^mKpoB oכ&Z(!j2PS;@zx_| @:ft)QiqO#k%Is$X;状vtL .~PR.$a%e9/]b,:OOp=*o+`$Ԯ4 ے 2& rĿ{l̰Q\a~pҞZ r.BEBrAqy_!d$0?¯=uYB]lA2;\:r\T;92~#ef> ӜvIENDB`Dd);  S Ahttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_equation2a.gifb6,%z{nr6,%PNG  IHDRckbKGD݊ cmPPJCmp0712OmIDATH픱kA/H#-% ? ئLgw{S(6ALai#ʃXX($ws$Dx`݋Sefo曙bZR99R;gu*gUe ./h($$X*]G; RKtPl/jZy09e )ˡhT/`3LsouڮVjl9n@(N>zQbR}Fq;1s̲JÃ!o`.΀^-):maj5D2jL׌LlY6[C'Fw!dz6N tt47c?ƚy+Vh%ӦZ4Vx'\L{o:N: wI)-&z\FA Pg"c)fg@*Q<7rQ,Q+Lsn!=ؾP$_wdjd( Dkcw<4!`#Qȩ8E9ɪ/QƁi~Auw~8pT;Hs|WH6$bn$rvl]n.R3(Wχ]~`o 1 ..e5,GCT V+9VҒ`=*iU(ٛ.T8/s| w%gIFxMathType001DSMT5WinAllBasicCodePagesTimes New RomanSymbolCourier NewMT Extra!/ED/APG_APAPAE%B_AC_AE*_HA@AHA*_D_E_E_A  (a0 * 1!) + (a1 * 2!) + (a2 * 3!) + . . .  = (a0 * 1) + (a1 * 2) + (a2 * 6) + (a3 * 24) + . . .  where 0 <= ak <= k+1ӻj(gIFxMathType002sIENDB`J(Dd   S Ahttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_04.gifb'Ifw` Q@S&&ʃn&Ifw` Q@S&PNG  IHDRPiFPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fDbPtRNS%bbKGDH cmPPJCmp0712Hs#ZIDATx^]vȺ= 'u{!pߵl :_:!/21ɌWU|G%@H_}U#k7Zx^vBfBcyn[ξ7\&ͲtGmaGUc\6>x㾃nl-kHUe_$Hqb9'O&{SB]].򴾍SYHI?Y?u'} qke{jTlR!AKq':|wN:;Qt> ( k'QF,}J4iop2Nz)և(zt9!>!VkXauS|%,<D.Ppc8ϓ8{xU.$4k:x).sfV^. 7Wn֫r]~]/׫sܭ︾CK+,PxMw ݏ;YaJux9L. Xw 43)@, ~CQxDl?z d'K", jAx<|d>F,^D,#xxFD8>Ky|@0ϱ54H o wAOOE}5%t&\(Y-W(fyu^,Wk wܝ􀮢AId ?ߚ@\>c$O 'EɽX7?bItJA7$`"TG k"؆(Xp.gsByN8xL&%((L% dN4aD1 LEL"0!]$5oVN"@2O@#]ТO:xc.3 P _R$yoX#@0@ z k"3%"*uR򋕙 ?,Td%'\9e&`eL AQ1?GB~o{>wKЀWx$~Qu:gFQ =079I" p<ɠ` @1* ToJF.Y/ÌxRˉ$<'9F%c K6 ݰ*Q6~'ߌ!)Rv#5`ei䧂(#?y*RS9y)_TjNjX?:n^lәo9@vKRPFqHtexc'.g,dYe=ZQpPVDbRH NY`3:N_1N0k8q' E nsy" ' Z"#1ȷYrC7)( & &L㇠Qbj B`O^Ar趻Ep|1ZL'u[\:@v\LOm2t"\D#@FhhJ8<߰Q/+7΀5=@9v<"(r$n4Pt.੢CaQNNaȢqJPݯ0NKoBlGeQF>aw`Pl:ك8hDL((ҹ0pe2OE1-azNi(%̛0LV7|c7+ +,bjmwrF:_d!t2;3Cئd(Rv~#pJ|L0NDJ’pi4DT;z=-8z JǞ`"JC2*D|AӉJ$8'zF`䄱IQJNS EL$p\4#\hSҿbt-Z(҉NGSx7>8@""2]ܩ;`H9Ĺ@(pˠ~#:ahfP#"Euep̅u}!,h_f06uE4@ ӈeNpE-pH'YF`,r\D6g-4.EV$U>(;D{HrxA͉4%hc$'VM̈%JAlcx&M4C2KdƱn9n"+vu|ÒKtBf'U2 >kMEw\& YvrB"I|ӣ|F3")K1G|PN;sʍK>: Z!4dEOj0JIz7<  IH0hpx p@!B!")!v'~Ɔ1#c% 4&sng7/"Lf u1G4E:$ \ vU=0֥57%b;,Z#S: (ƥ)Ma8nuĿc#,ɜ$YĀd2Mx@d~9Od>Ͱ:ί +Xu>obh a _Jk&ILľkI~)> LKL @6HEcnR$`8@? hC`kŰ4=t JM,#E\9Гc Jq΍!a1d@X ($ij#l28 =;o%F+S4vݨֻ߽Q7GQ#)„dd~ :njZqʉ/}I4:e\31 .NIIP:asO֊bK_^ঔ h?$SxTb5L .C#j<|}#zܬ"~I:JJCH.BS`?:rl1?lա4`m' "7q5clIR{QяcKb`@m:s0M-ζ#ph "`m0&dh:%Uw lTB@ &? >р tljTu%lD jč^,=& Nբiy_ƢTRW|qBN;*Siw4Zd* ')lS(xvR̡p {?KL2$k|V7kpbȂ=:+3SIϡ'g:r 9Md6_nC9d3IfÖP^CΒY'䚪t.{54l{Z+I;Qj/QsP&u/>hWVhOl ^7פ8ڶ=u}B3rM'[xY*.b_M̻嵿 f~,u٘`C%{Q`W2j̵FLd"bt)}Xiߜ3 %*ĝ ۸ @0m?o9,Z3IyI@gC_8mePr"4:jh̥NI.iTMV5:4>y?#,n&CguwܠHC_:s "guݿ0kUϨ'.{3]iE 獗.#zgR|uqΰ0׿.J8[=PyRQ6j$^rV؋j,Bg>Kzq xi( t/є]G'/m2Vܝ]ɺ}Д9)70Y?#Vȸ g+,߂`h :&}We]!bX*>y9OP< +yxj4xô) mdگSc4# O4*{'Ecw^jd Es\X<nXS* ǁ$.9rSd> y)!Ϳ <)l%[591|xD4OaL~{ݤa6IJas~2 EheF5yh%GnoN;>:bab?ax:7LrS6q"'fؘhT^[qț1 l\x<6HkC'N: _&%m2_Csg~ OUC_t o.[N@u$m iO3b*J~2¶Lpl2y:4vgu!)6M:% k'l>O!'nmuFF Sy00.qύڃohTdX>ts&Y]^w, Y\rb 2*~&LFp ?c v@;<^? V.ܡP!DK9MMDD<ѳX'| 6Q㰚(40Hڡ}b8yJ6/)ƫb^f'q3T$893WNh-$#,cZ,ԉhSmmD\b4ʃ)^OނH ɗtGk~c-nK .iyt0 XUޝTo/Ɉ8 8>l-_sSZ?Ʊ.L* Ң@s+A?49L'?5Z-%rhGUO9 RbAc0'8$/?j` Ԁ`F!"m=}Sxq1oE nDo.!#1*7@#2C *wC}[{¢/_wLfdaVcxDVm_hGL3SօUPӖ,AbWvAZ)Ta?ī2R-v/Nf?9MUЕ߃@`}+/ e*.y`䡆"T-thunx7(r`~EU)1Ŷ5 lK5s9FseZQ/<9#k'uQ%gih6 Aío`-L.[̧wړ^-{dV] =X,3LSX~u.16ڮT9l<ǽmZƓ!H eqeqY㯵/9-[(=U5`Z AMjZO[f9.[jNf:U$є_/Mb35 L  G=A~iZ\6&( G0nٶ{&@:/bkdV7Z_VůFw޻7xu}h|AXdߘ؞>A:1yK 7{ }Uz8^:/o\rSv7N~?:_uK09ԲUOʏR9e<2^W}m*ĝ9SGyf0 ao>X,'Q u뱲}sG=\>F6A{G~Pjhj;_ yDjuK+(нUiuE n"$0 t<"3[%ϯp%QpUBU6G /uF]K)F>碼* A3E5)|p=쿂rln(RygW̞%l7{ӏ̔B<,x;vn wuA&7ǿSEIc޸q]o&ր댽&;kDxMASNͫqHM$&)hYy^_͢e]#?sYtW/ˏփpɛq{V#`ӯ1#X?ͰM~MƯsu_QZ5~@Svnku ENc`qFcyۗYIYh۵1̦Bj>[A6q #斊M *NMPi4%Lp"UnI)O"+[iӇIWu||ҫ5*f,.&콴bgx(ח}b*[_عOX 51S{(['qfߞ2#.ve6A2_rWa[9`E_;;ܪgU8t?KV"N/*?܀}RkpuGdx=}wL٫%oΞ rˍjv;_,(ޓk9Q񷽟k=<[Y0By$ڽکTuzsAu|!ީ:ŀX< ͳY!gjzO~.t}f -j3 >߁Aνt}w<-&#]UfI:NΖB6Ӣ+9 hJv7WatKΑy9?} AMn67Vx}gcdGxy$eY!oϭ۩y5lg&CYGt-/*^]pܖC39 ^G.6S@pS;pSv@V 37Iu7)kvbA r3,67XH͔>۴=TȲ-Lؙ.# c˦^G.uB<|og}x /Mi3B%KNs ̝cAh;i59u*-A9̙)^wMۗ"'b smכ]uQ aSzN )]H#/ljT[X=b"s`1b!_Z!~O(Ԯ4ъEtP2fk2OyO_74)TSb4=g$y '\Ckws};.m{W¼xZ1<-$Mu:Y̒9<;by2Ilb6K.SJX]׿UԏFXbuf4Gh0nyŬ+Qf}m8s+=TijmNn/n_ v- NIENDB`-Ddk   S Ahttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_05.gifb,hgW_,nW,hgWPNG  IHDRDPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fDbPtRNS%bbKGDH cmPPJCmp0712Hs(IDATx^]v8Ns5YK'r6Rj;;+(H)@J$7=-o >/[jS rU.-˘V_{08_jb KkB:|igvmd̔a*=\- WUC>\. {v2qT7nQYHxXV_rVܓeyz4ÿL0ϻk|gg8KgX}8;;=˰1⫟vgݬaYvaY<λ<`l ,`AwO.Er~J~f`4E~4F(/bTp>ĺ,wow=gXKÃ'>'~q>?b_ [J|aaYm%}s3we?V ;pYeVe}x<dqO؃-"^].rHX?c{p90n7 yN((ვ*×b& DBpEεr4v 0+Mj4*DE~U. oB52PpwwwwO@-'l Z`0='(XY&^@&Hb'i L l{zZ!0#%q@/"` fgK6O72/A-b9E75 ZH| Çs ~ ]uWX ؛_aERb$ڑs7QH_z`< GC9" )H+ $q^*XO("cKd7@<e󋋿_{} gOP@D@K {Oq (Q;v#`ĊSA{+;rR3 ,\v̋K~KCdB6 alva'~- H?9c&n4RS`#<9f$&@dx lE)䞠F'8ha;[ujgշw;?g Q O4N(sX}{H ׺D k"6?뜆3Lk Q=ע@0!Ѓ༤n`т)%`"j"-1{9A6 wf3AQ`'Dl,t #G!2Rx ;)&x+:X?oJ9,NOQ/fL~4PY luvιsQu؇>Vt,AIyOH:rG5L 5K9k'0SKP,+(;GntEaUSIJq*N0<HU)Z l.Ep* !2^J>ᝇONɷv8cYN[_}w:>3@E"X)~gfy}~E\Q۸EX. ;: MI HAq"pRxD &RN%F RDU1 )6(NHrSF7G&a#@;9(" .ބC Įj BdVfAJ$r5ˀ.a%xӥ;-qN4f`q=bI sE?.vX'29C,aҖτx< π勠WL K(Hh;d*TV E YtzNX"6)(ac&u0Bd?R} UE}@JY UMō AQӉkHJ +rF,u~$}=[, CK7T % &] SQ+֊R!h@z ʻRJ 41Qz @< #U S@ۅ&KR0 s GhUJ.y@O=:a8{5M8 8Cs&W;-4!{Z=@BqrF-*A߭N;$&%&:z v$Oyg\uHP ̌K.cPrJuVj( ,N#AQU4 hgsکo's1Y gA8Vd]t#dw _r&=b-"%Hl"+CVr%J^i`HެUi,egf7 Swmu:Aeg?3iZH$j IڠGB&rp1VaZ @2m~Ӓ #ī}60V E€{&랡A`Q4[{ΉOC1A.|B0$&MůK>@@G]A/$ @9-UԿa GEccZSCfjk}ɿ9",)@ŽbbqV(3鯋'I(4I38Hvze7ٰ3]w%tz6͟:Nvɮ;>#T Ui#Xly+ eJx& ^D6rYSxg@Ik(AE'sAMmP G7)۰ E K؆_Q1"F)//TpbX*jٶ;,lT sR#d*EQGi a rQGܔgTsV;O(JT'v/%Oicj(F0΄pF@N1 L;'L#E'*+-y9 D&X4x=') ֟.v $D_8%x% $ؘpRAb5]"Z_>7ơ՚+␛WkX*@L39䤸"71z MMǖ #M$bCXMvl= _3]e`g~a5&Uq饡)T&]l5ӥm5B&^\k9n1)פAyΦtͷ v5NƘY3s8˱sLz8B5TȞxe`H6$h,:yU,3^ܭT5ȻM:!OVvz'<ͼW3>v*qGo E/jXyKylumMF8Ya=S =}@=sUУ37&?NeZj*=тfƧEs1ª['\dls6&:>襗5e2s/[=>ĺw5JWsGk$^Z !efM={; c2ƩݼXRSA̖bXf*vfX H}31Jk#p(w2s11M9-Du-[;ۊ6!oQ6Zc/J#0ѣe|>#oTwi\(4\,[ڙBMnZYT(PB?myw-}N,f= ?sQXK#P+*Olɜk#ർewyafM:x]ϿB M&?S]NzlG ,w\⫕|cVT~ o),`Pqt vjgZ <:$hV;!>\}9c6.liMVaW2--0tb) 41r 9^ʁ\Y ;5)([F;c,t sLEX*Ļ5!>|/b,r*Q% e$vWcY6&!ޘ^x8,Fa~wVek2ȇԒ;N<۩~X#j*)+۟+O|U7<2uS^qT 'w~=գ'=*OYB}䬅ڠЃ~gkR±WyJwPV@XHmzLʕmOpiOoyugYyyV6ӗ!)bkl3~Vf(賌L=t=Հ73<)e;6ɫK~@1X+}OףOHU8cؙ}֠ZXwo#n.#s/J`gJJTrs"^%_5bm[~rY>\m~>L\EL%{{16րͭU'O?#62aYNZ44)65] Zc/lAlW[B{gYw]NN߂ )q/jrZ yT#z|[%嫴:bGsܓ4\[_Li ^y;e|<'rJSyQV<ֶ>3ַhg8ַ.yo7Ԣ0ߥhI=U}5Y%`_X׶q?r1yi{Am6L4g޽*Uuͷ=EU_uȮZ~~p*Tw@[y !݋q܎] ~Sew}̊׽bZ5Q]vl,R]o;Ƙc5w[vxu0m^IOQ>F W8Whstyv! ЈM*{i *}'?XɵGr MnV~u[uA7Z`,[d[X{/l\Y>is1軜L57;s:xoRuToH _vD{K/z0vNo(qkbwwU27V٪΁`8~:vU@I:('yٙwkM $pWtybd5ayѫz6,bLiÛi|fQ!u"c}5a3qe4X&ŹNR?62\mp\#]=lrgG[S\Udz ,EU^pԦ i7sLLӹ+^=7!U^;keV?J)4 4,f̓$xx :)tnUFVqT1x}W#Eqَ3`Jk&Uwf5*޹%22BU3wU_o[8˿K̿VsE5ho W]ӫ:+VIݵQF ]%z){Vր߹*_DknBp3qV.mSm'nBP{PcCkw|mY[J3M\eIjlʥ5nr t!۝ytUv*;y+{4vgI \݅ q3GvM?VybЂ:ٙ|(|4,F!6&+ w.VUNyho~<WG3ӞՀX~̭ms8rNA4fpIxo\ukkvfS Gz5;HJ]'6;Ԛ1jS,7Y1vw|qwP#4ȼ˔l7\(̌y(1F(˄k`vf5Z4#)aC3-q4:*|2Ww22Pwջ`x)pEf _nTxf3ŋ/*|sspLvf=_%grBWq E}5k).ƨpwJXW(MyTv3]Wz~f[K3oIXЗyz,~cG`j,8h#g6\vl(QWzls~ƂU [h6,UУ6* hĮ⛧abѩ,'#uv>vojLuҩVnRw~߄]:UuWjXxkaL~\E9%τ &3Ƥ @9UY@dD3?ʏyW^Xwr(We,yY}x/,N~ Jj&:tФȆqFSR1C>I8@:/}Q.k%4+XاϿ=2wC)eҭx{(&狲żSa߷CU1:ʯMKmĨ8[qRQKAUYBq=|il)vLѠr\*m --u=xvbL4 -Rk[\: ͂vfIw-v\_8 iOct4WAl1*HZ|Dtb^Q=&dfKc*pVjH[UdL4V+4-P aS`6)fSb:]#g eNtMޅ<1jF#F+jU̿z$ f4-}tVA#QZiu D 5P 80Jx%S4LإRKW.YAɦKB|飡|ƁHQ:a'V'tiBn1S0,)3TƓ,Lt}+y>c4ٔ @؇WvQA*ŢavC, Ɇ=5M: sq!;8s#[?҇;Cs*[7[ 7  T|IENDB`i/Dd   S Ahttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_06.gifb=.wb8dLzzj.n.wb8dLzzjPNG  IHDRvPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fDbPbKGDH cmPPJCmp0712Hs*IDATx^]vHu%'t z !sjK'uм̬9sJ@F$DSVf ZEQx-֗BʸgY -GpKndYsjX zn[F;Zg}ܲ\,=gHeU.% 2Ѝ<U6Cd\wN T.^b/=D8lNn4Ȭ+Y=p=m?^/؃uW`nk{pl=u^oYo-g1̆tKv%,<ϸ]\>"[6,G"8GyvM<}u^FXÖ۸콻¢zv~w{w=G=KwXC=w}+e^xC_,@T|qWv_s ?MJK>P&\Ϻw3%xuXgvx`e > +``G (9s2@q] >bC`N:DQX'?Q؜P[fNPvsw{r;2:p@ v,)Up'\ -M܂@oNȹNXX3P q"d^87ߑ`Y=#<ސ{Hp'dGF⃄ÿ6$@8 )?|'D3ʀ ] ۤ8Ē?P nRNs QD16K\Aa@Jsl7S;43]:+G\8깿NѸ\ٯH0I_9)JPlnau@ 8 z ["0?K6EN껊߽Tl"(63 2/(0G ,3GI|܊d$d7D/=b/D+! ('ށu8}*x(zpY?T_;d|_hȁeQL/n?Ǐ7!)Rn} h$ ?A9Qx0 vD-"HAӝƳ4J35'CaBD2R>w3:\}lsC,&B}1dCHS+[mic螵Z Ϻ"znꡬ@Z S`29.߇fxVÑZ-`Tsmt!c>c2Ä A,ވ| ԻErC>qv 9xG}B "fP!.p ˈܲu-@=9!| _o?Bt\ś .&bDh {@F$qÍJ {<511;jex6k,ot8d!6څGbJnMG!y DV~Sک*G@힠E~]jBY >>8EXE x g{6{&TЌ T.<#Z-!j_N h7Ye9X:D#&#v$8 hq~ @.;'+Lx]B(TqMBxBڔ":!Bac|_ HFd̑r]~ȓG}()֑KmP=tkD\'  GA6Z-[\Q 2LD:tk!Ǐ#mIGNFv;Ψ8%]NI7_`A X$43"Q- мzN@ " =6L-bKd;9iF^>9X`~Sd]<:yJq yB@'S%"[,«±ER,,)-Ƽ(05| Zn% &n3"Kh07X)₃XTp"6o cV !*J4MdtȑhW[-2†1|=w_?z._/A 1З%&oUzt f%B(@Lÿx$2@ qD0]hYhG300 /, A3\9Ba# ⩁Qr"#Eh@ZzΫ5d1lJf$=pD¯ ]#.dIE |w8)hc>-t3,YK?Mg[%0ySIգHL2XM)C% a48$C7Qĥ{OD[ىѰap:",iaB: wУG(6E-zy1`0X)LٕД0sĦє/@1+B (ş$%/dtO7 lg(O?CZNl6N'^hŸT`[WKA0,iܒ{'&^1@ =^EKKd; wHXEaQ^7 >9#5`H4sƾ %幊L;Da\8ЃcJIɝ 0䕡  ģ#j17 =:K_v%t/YNw>w;\^v(p__d LlKE)῱{}H%_ 9hbJ.Sv3 a7l1 &'!6A;=*B9. TΠ6%8%$ap-`ts$ˡC7d7R@7=G1|qHHqEbJgG_}=Ç8}:T{BC.9CY@0H8';{- j.5oy VAr?GrnvEwӁr ?!}l $~-NCO`^BfvC]rj#Y83 an{ +O>IA1Q`h :MْjS N@r3Zw=JS9'@'lX)##</C{=`Ӹ_DBKLo׿C'DH Ӥ,ͩ]A`x *r2˩P 1',6C9^|wXqc+I>ɲx6_QNHc6rmNU`zف܇?u/МeZR5$^;t;^QPPy9fܒn%Pͩw '%s}bsol- ƪ EO[ŴO֮-1p|Ij6-~o=Ki}6emT$i Le s_fa -M2WI5MDjf^ ~g(-Y#-k Kx`:{2+X I*iMؽ @%gM+~բDsBA7QMH%D{N=W_BB&ߍMWxuFλꉗQZ.0:?j#n3әY_i eX M׷SVwcݷ'\NaXѯ1;aG¯JjUaOΰk9|wtړ) 8YQt9"~/:[XKK AbY6|!p[zTϜ^ږO :>?1/W,r'-ǧ+/9ɽZv^_Л[ᇍooyE*?n@uc=7Im]R_<\LKD)z)iN4m\3Bƕ(O UeףIeMosqNkCARmD.r=i5H&O9d6"JnzMDBrǭiP:Ab(eڣowc5f$\Hl絜ۄ H䥦吽E\ ܱOj=,^1 qKf[ή"s/IL 6gk~"($n3Q[جcm*urrë>*Δ3yepWA&ȉZbUR9~L[Ha L&Dđ0Fda)J˘5}xDsDKI{b23s&nYS\R&pXNUZ㑖5hcf uGPĶlZxC-1+ɷl%nO=&Hes_PSN4YG,hO^9q&O19̱8B/ra~K 6eeY{WPcDp`璬ګ)t!Lw|ß-|iŏZ0qnD Yj!s˫>ɷ\MX7")'sfH'Uc\N4WpeG#g-m汎#p9G#n)=;! qA;|qU_)[VkMs A*993G7j4.k~ BĻs99sK輚V9}8jJuEBϪJ Ŏ)g(By~yy(57_-ڒ0輼p,H1v`XS:p n)sgvAGS]̲t7~F`(U!8+ϔŽ隹G?j%<7}|q~̪N!zPqȟy17G¨ ZC#vܸ+xi۸ڀG&}8f檋B5.9䨇0i66ٓl,L7kvbIаlTSkA "y=5ǽ>۶G ¢Cvzf\J/: n3.)wP掠p8ÂR-ـm9eMmH Rp.F$|ع*'D4?3x~|"D(*m lBRwy(% .Ěif{1)s^ZcX-۲^Ni2x~zNm(&˖2}ftYAX:S=fcٌ#jpAU_·,5l`:_P|(=Yj֛s붯`1k8WKNN`Йck4<5}O9ۻtϙl05?zzn!0N_='gse0r\MM粸2)p'9vf%\{oƉ9猍~`NwBWe+-a~P-j9$ }3jj|tz}"2OzB֞Y~0fW#inc(-o2VL#yq2'tX80ͥCSG'lƇ?}r:CY{D0~ [cMjl"];؝ˏzvC]W`f0#9^1-׹*n2`~' 9kƇoqUE%ȷL'R3,L'JUzn!ۛCb si l}.O *Oku ԫCk9F'|'YB/σklضai>79Z2)czxolːBDO?E9q4~▾g41"wа?4YFь[4k I K&;СW'X f 3I=uPh[J}Kـg^HK^]:c[g쾿fݼ_a4K [s~"3Y5tS%@q<-WH˚'svNY>c?jU8dƶ=Rͷd+! 5E.LI_ ,ul0 K̒-<\amNM=g'α9A籯e-t~`f[DGwmyu+z/1hjG>>2iRn(~߭ޣG?bS3opRNWq0V9R[Q_smsc6N^*휲cg[J$[0N]e0ƀDkGy( t[|Kfw57PoIs,H%fl! OD~TKm*a nq"ٷf AWeN( |~xD~ZaUFuq]¹iApljC,+޷y f3FdA>L`b(5+`[?79Bόqzl-Dtk:an:.n,λh_ѧ+Im ss1Ҳ_W(sSyZg][V8 5?zy?NPѹhC9"tZ4YRSɴGa]96sfn"8GaojZ񣯖&1$OJFaqn:pͤ|'.36K[?.w8'sV'Ȕ_wmSq1;^7crE\l scV~N.q̝дcuK]G*&OfG9 kRCՁn%ހf.,%X5E@/L\DJJ˭IslqwWL>*I_IK/\{>\e4k9״\ɍ13c5q͜;N4ztޛ,f>l|]YEqUZZthJdžTISR_#QQ;9kv$2_k1Bhst:(-6kSGXN|;gLXԉReI DYW{nN1} ʤ٨u n2[*MT*a^4rZJ [IC~/ѭ9PӉ[GY,OwK[p'6SA2fl6ɧi>MY>&|')YǾj6Mq56˧y>˦clNƳ Y:ɳN6G8ptht%;Xatjӽ8~OKAg]egiNQ=, r *Z3#}IENDB` i@@@ gQe1$$CJKHPJ_HaJmH nHsH tHD`D jL 11$@&"5CJ(KH$OJPJQJ\^JaJ(P`"P jL 2d1$@&\$"5CJKHOJPJQJ\^JaJH`2H jL 3 1$@&"5CJKHOJPJQJ\^JaJD`BD jL 4d1$@&[$5KHOJPJQJ\^JA@ -k=W[W.U`. #P}>*B*OJQJo(ph3J^`J gQe (Web)dhx1$KHOJPJQJ^Je` HTML PreformattedS 2( Px 4 #\'*.25@9-D1$M CJKHOJPJQJ^JaJ@o"@ figdhx1$KHOJPJQJ^JDo2D labeldhx1$KHOJPJQJ^J~EQ}{ e   +Ig7;TZ$Jo$%7^ 5 *+LRpLc/0K2V-b!!"_$y%%%%%&&&&3&5&[&m&n&&&&&'-'.'T'|'}'''''''5(y(((()R))**++{-../=1G1Q1[1e1o1y124445{5:666V7M8999999999999:: ::":#:%:1:=:>:@:L:X:Y:[:g:s:t:v::::::::::::::::::::: ;;;;';3;4;7;C;O;P;S;_;k;l;o;{;;;;;;;;;;;;;;;;;;;;<<<<#</<0<3<?<K<L<O<[<g<h<<<<= ?5?r????"@M@n@@@@@@@AA=AAA^AjAnAuAAAAAABB BCBDBeBiBBBBBBBBB.C2CFCJCKCbCCDDDDDDD FAGSGGGbHtHI'I9IKI]IoIIIJKK2MoMMMMM4NXNNNWOvOOOOOOOGPMPsPyPPPQ QQQ[QpQqQQQQR RRZRRRRRRSS&S,SISrSSSSSS3TXTMUWWeXuXY[[ ]]__`ab9b=b_brbsbbbbbbbc$c%cDcHcqcxccccccc d!dNd|ddddd e>eBeiemeeeeeeeef"f;fj 2^.΄]هJk̈ċǍ_jBS v0000000800000000000000000008000000000000000000000000000000 0 0 0000:00000000000000000000000000000000000000C0D0000C0D000:00000000000000000000000000000000000000C0D00000000000000000C00C00000D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:00000000000000000000000000000000000000000C0D000000000000000000000000000000000000:0000000000000000000000000000000000000000000C0D00000000000000:00000000000000000000000000:0000000000000000000000000000000C0D00000000000000000000000:0000000000000000000000000000000:000000000000000000000000000000000000000000000*000*000:008000 %2=>/@G2Xv7c )y,:=[>>S??O@DFKMsTWhkkocMœr+8:Srt.TVnyb!!!***5w5y5:6662>>>bCCC_LLMS/T1TaaagxgzgxyySAҖXXtXtXtXtXtXtXtXtCtCtCtCtCtXtCtXtCtXtCtXtXtXtXtcm^ h #+.ehijpq  kl  +%)e l  IUgs?A`c,2RYw~ -5 /5Xavy/IR[il!&8=4Fu ~ I"K"L"M"""%%%%%%& &&#&7&9&_&e&p&t&&&&&''2'4'Z'`'''''''((7(I(((((())")e)h))S33333333333333333333333333333333333333333333333333333333333333333333333333333'I9ISjackgC:\Documents and Settings\Administrator\Lhb\Using Permutations in .NET for Improved Systems Security.doc,Qgr킁^`.^`.pp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`.,QgLR*^&8PMh@KJ99999999999:: ::":#:%:1:=:>:@:L:X:Y:[:g:s:t:v::::::::::::::::::::: ;;;;';3;4;7;C;O;P;S;_;k;l;o;{;;;;;;;;;;;;;;;;;;;;<<<<#</<0<3<?<K<L<O<[<g<h<@Lm(_`P@PdP@UnknownGz Times New Roman5Symbol3& z Arial7&  VerdanaI& ?Arial Unicode MSC.e0}fԚPMingLiU 1hU{V{d}@ !?!),.:;?]}    " % & ' 2 t%00 0 0 00000013468:<>@BDOPQRTUVWZ\^ \]d([{  5 0 0 00000579;=?ACY[][77x2 http://msdnjackjackOh+'0p  , 8 DPX`h http://msdnttpjack//mackack Normal.dotjackl.d1ckMicrosoft Word 9.0@F#@_(@,#Ld}՜.+,D՜.+,8 hp|  1/ @  http://msdn Dd 8@ _PID_HLINKSAr\Emailto:jmccaffrey@volt.com@^BAhttp://msdn.microsoft.com/msdnmag/issues/02/06/crypto/crypto.asp?Ihttp://msdn.microsoft.com/msdnmag/issues/02/09/SecurityTips/default.aspx/<Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutations_generate&6Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutations_applyingpT0Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutations_successoroW*Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutatations_kth{[Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutat_topic8{[Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutat_topic7{[Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutat_topic6{[Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutat_topic5{[ Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutat_topic4{[ Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutat_topic3{[Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutat_topic2{[Shttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutat_topic1x1chttp://msdn.microsoft.com/security/default.aspx?pull=/library/en-us/dnnetsec/html/permutations.aspyL"Jhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_01.gifzL%Jhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_02.gif{L.Jhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_03.gifx9Qhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_equation1.gif>E:Rhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_equation2a.gif|LGJhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_04.gif}L0XJhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_05.gif~LwmJhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/permutations_06.gif  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghiklmnopqstuvwxyz{|}Root Entry F8YData 1TableEHWordDocument2~SummaryInformation(jDocumentSummaryInformation8rCompObjfObjectPool8Y8Y  FMicrosoft Word MSWordDocWord.Document.89q